package org.cqupt.differentFile;

import java.io.File;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 主要的处理类
 * @author liuzijie@meilele.com
 * 2015年12月7日 上午11:27:44
 */
public class ProgressDifference {

    /**
     * 操作临时目录
     */
    private static String                     operTempPath = "E:\\comparetemp";

    /**
     * oldwar包的md5值存储
     * 迭代过程中，hashMap的key值会变，如果不用concurrentHashMap会抛异常
     * 
     */
    private ConcurrentHashMap<String, String> oldWarMd5s   = null;
    /**
     * newwar包的md5值存储
     */
    private ConcurrentHashMap<String, String> newWarMd5s   = null;

    /**
     * 老文件的绝对路径
     */
    private String                            oldwarPath   = null;

    /**
     * 新文件的绝对路径
     */
    private String                            newwarPath   = null;

    /**
     * 主要处理方法入库
     * 
     * @param oldwarPath
     * @param newwarPath
     * @param blackListPath
     * @return
     * @throws Exception
     */
    public DiffResult progressMain(String oldPath, String newPath, List<String> blackListPath,
                                   boolean unzip) throws Exception {
        DiffResult diffResult = new DiffResult();
        this.oldwarPath = oldPath;
        this.newwarPath = newPath;
        File fo = new File(oldwarPath);
        File fn = new File(newwarPath);
        //1. 准备
        init();
        if (unzip) {
            //2. 解压2个文件 到临时目录 
            WarUtils.unzip(oldwarPath, operTempPath + File.separator + fo.getName());
            WarUtils.unzip(newwarPath, operTempPath + File.separator + fn.getName());
        } else {
            //如果不需要解压，复制文件目录到临时目录
            FileUtils.copyDirectiory(oldwarPath, operTempPath + File.separator + fo.getName());
            FileUtils.copyDirectiory(newwarPath, operTempPath + File.separator + fn.getName());
        }
        //获取临时目录的文件
        File oldFolder = new File(operTempPath + File.separator + fo.getName());
        File newFolder = new File(operTempPath + File.separator + fn.getName());
        //对临时目录的文件分别遍历求MD5，如果是文件夹存-1 
        traverseAllFilesOld(oldFolder);
        traverseAllFilesNew(newFolder);
        String oldMd5, newMd5;
        boolean flag;
        //3. 2个for循环遍历map 跳过黑名单文件
        for (String oldKey : oldWarMd5s.keySet()) {
            Iterator<String> iterator = blackListPath.iterator();
            while (iterator.hasNext()) {
                String blacKey = iterator.next();
                if (oldKey.equals(blacKey)) {
                    System.out.println("黑名单：从[" + oldwarPath + "]中跳过文件[" + oldKey + "]");
                    oldWarMd5s.remove(blacKey);
                }
            }
        }
        for (String newKey : newWarMd5s.keySet()) {
            Iterator<String> iterator = blackListPath.iterator();
            while (iterator.hasNext()) {
                String blacKey = iterator.next();
                if (newKey.equals(blacKey)) {
                    System.out.println("黑名单：从[" + newwarPath + "]中跳过文件[" + newKey + "]");
                    newWarMd5s.remove(blacKey);
                }
            }
        }

        //4. 根据key对map进行比较 输出到不同的map
        for (String oldKey : oldWarMd5s.keySet()) {
            flag = false;
            for (String newKey : newWarMd5s.keySet()) {
                //如果是同一个文件
                if (oldKey.equals(newKey)) {
                    oldMd5 = oldWarMd5s.get(oldKey);
                    newMd5 = newWarMd5s.get(newKey);
                    //如果MD5不同
                    if (!oldMd5.equals(newMd5)) {
                        diffResult.getDifferentFiles().add(oldKey);
                    }
                    flag = true;
                    break;
                }

            }
            //一个老文件在新的文件目录下都找不到 则视为丢失的文件
            if (!flag) {
                diffResult.getMissingFiles().add(oldKey);
            }
        }

        //如果一个新的文件在 老文件里面都找不到，则该文件为一个新的文件
        for (String newKey : newWarMd5s.keySet()) {
            flag = false;
            for (String oldKey : oldWarMd5s.keySet()) {
                if (oldKey.equals(newKey)) {
                    flag = true;
                    break;
                }
            }
            if (!flag) {
                diffResult.getNewFiles().add(newKey);
            }
        }
        //5. 替换

        //6. 压缩war包

        return diffResult;

    }

    /**
     * 准备阶段
     * 包括删除操作目录下的垃圾文件
     * step 0 : 清空指定操作目录
     */
    private void init() {
        FileUtils.deleteDirectory(operTempPath);
        oldWarMd5s = new ConcurrentHashMap<String, String>();
        newWarMd5s = new ConcurrentHashMap<String, String>();
        //blackListPath = new ArrayList<String>();
    }

    /**
     * 转换老文件到 oldWarMd5s 哈希表<br>
     * key 相对路径<br>
     * value md5值 [PS：文件夹值为-1]<br>
     * @param dir
     * @throws Exception
     */
    private void traverseAllFilesOld(File dir) throws Exception {
        File[] fs = dir.listFiles();
        for (int i = 0; i < fs.length; i++) {
            System.out.println(fs[i].getAbsolutePath());
            if (fs[i].isDirectory())
                oldWarMd5s.put(relativePath(fs[i].getAbsolutePath(), oldwarPath), "-1");
            else
                oldWarMd5s.put(relativePath(fs[i].getAbsolutePath(), oldwarPath),
                    FileUtils.getMd5ByFile(fs[i]));
            if (fs[i].isDirectory()) {
                try {
                    traverseAllFilesOld(fs[i]);
                } catch (Exception e) {
                }
            }
        }
    }

    /**
     * 转换新文件到 newWarMd5s 哈希表<br>
     * key 相对路径<br>
     * value md5值 [PS：文件夹值为-1]<br>
     * @param dir
     * @throws Exception
     */
    private void traverseAllFilesNew(File dir) throws Exception {
        File[] fs = dir.listFiles();
        for (int i = 0; i < fs.length; i++) {
            System.out.println(fs[i].getAbsolutePath());
            if (fs[i].isDirectory())
                newWarMd5s.put(relativePath(fs[i].getAbsolutePath(), newwarPath), "-1");
            else
                newWarMd5s.put(relativePath(fs[i].getAbsolutePath(), newwarPath),
                    FileUtils.getMd5ByFile(fs[i]));
            if (fs[i].isDirectory()) {
                try {
                    traverseAllFilesNew(fs[i]);
                } catch (Exception e) {
                }
            }
        }
    }

    /**
     * 将绝对路径转换为相对路径
     * 
     * @param absolutePath 临时文件存储的绝对路径
     * @param filePath 原文件的绝对路径
     * @return
     */
    private String relativePath(String absolutePath, String filePath) {
        String str = absolutePath.substring(operTempPath.length() + 1, absolutePath.length());
        File f = new File(filePath);
        String name = f.getName();
        str = str.substring(name.length() + 1, str.length());
        return str;
    }

}
